/*
This file is part of MMM.

MMM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

MMM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with MMM.  If not, see <http://www.gnu.org/licenses/>.
*
* @package    MMM
* @author     Andre Meixner
* @copyright  2017 High Performance Humanoid Technologies (H2T), Karlsruhe, Germany
*
*/

#ifndef __MMM_SENSOR_H_
#define __MMM_SENSOR_H_

#include "../MMMCore.h"
#include "../MMMImportExport.h"
#include "../Model/Model.h"
#include "SensorMeasurement.h"
#include "../RapidXML/RapidXMLWriter.h"

#include <string>
#include <vector>

namespace MMM
{

class Sensor;

typedef boost::shared_ptr<Sensor> SensorPtr;
typedef std::vector<SensorPtr> SensorList;

/*! \brief The public interface for the sensor classes */
class MMM_IMPORT_EXPORT Sensor
{
public:

    /*! Checks, if the sensor data applicable for the given model */
    virtual bool checkModel(ModelPtr model) = 0;

    /*! If the sensor contains a sensor measurement at the certain given time, it is returned.
        Else if possible the sensor measurement is interpolated.
        @return Sensor measurement or nullpointer.*/
    virtual SensorMeasurementPtr getMeasurement(float timestep) = 0;

    /*! Returns the closest sensor measurement in a given delta around the given timestep.
        @return Sensor measurement or nullpointer.*/
    virtual SensorMeasurementPtr getMeasurement(float timestep, float delta) = 0;

    /*! Appends this sensor as an xml representation to a given xml node.
        @param node The xml node.*/
    virtual void appendSensorXML(RapidXMLWriterNodePtr node) = 0;

    /*! Returns a section copy of this sensor.
        @param startTimestep Start timestep of the section.
        @param endTimestep End timestep of the section.
        @param changeTimestep Section begin at 0.0 or the startTimestep.*/
    virtual SensorPtr getSegmentSensor(float startTimestep, float endTimestep, bool changeTimestep = false) = 0;

    /*! Returns true, if the sensor contains a real(!= interpolated) sensor measurement at the given time.*/
    virtual bool hasMeasurement(float timestep) = 0;

    /*! Returns all timesteps on which the sensor contains real sensor measurements.*/
    virtual std::vector<float> getTimesteps() = 0;

    /*! Returns a map of sensor measurements according to their timesteps. This method runs in linear time.*/
    virtual std::map<float, SensorMeasurementPtr> getMeasurements() = 0;

    /*! Checks if sensor type and configuration is equal */
    virtual bool equalsConfiguration(SensorPtr other) = 0;

    /*! Returns the sensor type. */
    virtual std::string getType() = 0;

    /*! Returns the sensor's version. */
    virtual std::string getVersion() = 0;

    /*! Creates a copy of this sensor. */
    virtual SensorPtr clone() = 0;

    /*! Returns the minimum timestep of all measurements of this sensor or -1 if no measurements exists. */
    virtual float getMinTimestep() = 0;

    /*! Returns the maximum timestep of all measurements of this sensor or -1 if no measurements exists. */
    virtual float getMaxTimestep() = 0;

    /*! Shifts the sensor measurements by a given delta value. */
    virtual void shiftMeasurements(float delta) = 0;

    //! Synchronizes all possible sensormeasurements on a specific time frequency via linear interpolation.
    void synchronizeSensorMeasurements(float timeFrequency);

    //! Synchronizes all possible sensormeasurements on a specific time frequency via linear interpolation. Removes all measurements outside the given intervall.
    virtual void synchronizeSensorMeasurements(float timeFrequency, float minTimestep, float maxTimestep);

    /*! Returns the priority of this sensor. The higher the value the sooner this sensor is in the xml representation of a motion.*/
    virtual int getPriority();

    /*! Returns true if the sensor measurements are interpolatable */
    virtual bool isInterpolatable();

    std::string getName();

    void setName(const std::string &name);

    std::string getUniqueName();

    void setUniqueName(const std::string &uniqueName);

    std::string getDescription();

    void setDescription(const std::string &description);

    /*! Joins the sensor measurements of two sensors with the same type and configuration.
        @return The joined sensor or nullpointer. */
    static SensorPtr join(SensorPtr sensor1, SensorPtr sensor2);

    /*! Extend sensor to given timesteps by readding copies first and last measurement */
    virtual void extend(float minTimestep, float maxTimestep) = 0;

protected:
    Sensor(const std::string &description);

    virtual SensorPtr joinSensor(SensorPtr sensor) = 0;

    /*! The name of the sensor. */
    std::string name;

    /*! Optional unique name of the sensor in the motion. This is set when adding the sensor to a motion. If possible this matches the uniqueName. */
    std::string uniqueName;

    /*! Optional description of the sensor. */
    std::string description;

};

}

#endif // __MMM_SENSOR_H_
